﻿// Inner Fire 游戏引擎库
// AnimatorPrinter - 动画状态机显示器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于打印信息，骨骼状态的粒子等等。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-30

#include "animator_printer.h"
#include <game/animation/animator.h>
#include <game/object/instanced_sprite_object.h>

namespace ifire::game {

enum DataType {
  POINT = 0,
  AXIS,
  LINE,
};

AnimatorPrinter::AnimatorPrinter(Animator* animator) : animator_(animator) {}

void AnimatorPrinter::SetSpriteInformation(
    ikit::sstr type, InstancedSpriteObject* obj) {

  auto avatar_nodes = animator_->GetArmature()->GetAvatar()->GetNodeTree();
  auto armature_nodes = animator_->GetArmature()->GetNodeTree();

  if (type == "BonePoint") {
    PrintBone(obj, DataType::POINT);
  } else if (type == "BoneAxis") {
    PrintBone(obj, DataType::AXIS);
  } else if (type == "BoneLine") {
    PrintBone(obj, DataType::LINE);
  } else if (type == "Avatar") {
    PrintArmature(avatar_nodes, obj, true, DataType::POINT);
  } else if (type == "AvatarAxis") {
    PrintArmature(avatar_nodes, obj, true, DataType::AXIS);
  } else if (type == "AvatarLine") {
    PrintArmature(avatar_nodes, obj, true, DataType::LINE);
  } else if (type == "Armature") {
    PrintArmature(armature_nodes, obj, false, DataType::POINT);
  } else if (type == "ArmatureAxis") {
    PrintArmature(armature_nodes, obj, false, DataType::AXIS);
  } else if (type == "ArmatureLine") {
    PrintArmature(armature_nodes, obj, false, DataType::LINE);
  }

  // 将项目的Transform同步
  obj->GetTransform().SetWorldMatrix(
      animator_->game_object_->GetTransform().mat);

  obj->SetRefresh();
}

void AnimatorPrinter::PrintBone(InstancedSpriteObject* obj, int data_type) {
  auto& list = animator_->final_mats_;

  for (int i = 0; i < list.size(); i++) {
    auto& bone = animator_->armature_->GetBone(i);
    auto node = animator_->armature_->GetNodeTree()->Find(bone.name);
    if (node == nullptr) {
      continue;
    }
    if (node->avatar_id == AVATAR_NONE_ID) {
      // continue;
    }

    Trans3 t(list[i]);

    if (data_type == DataType::POINT) {
      obj->SetPosition(i, t.GetPosition());
    } else if (data_type == DataType::AXIS) {
      obj->SetTransform(i, t.GetPosition(), t.GetRotation(), t.GetScale());
    } else if (data_type == DataType::LINE) {
      if (node->parent && node->parent->bone_id != -1) {
        Trans3 t2(list[node->parent->bone_id]);
        obj->SetLine(i, t.GetPosition(), t2.GetPosition());
      } else {
        obj->SetLine(i, IVec3(), IVec3());
      }
    }
  }
  obj->SetDrawCount(list.size());
}

void AnimatorPrinter::PrintArmature(const ArmatureTree* tree,
    InstancedSpriteObject* obj, bool is_t_pose, int data_type) {
  if (!tree){
    return;
  }

  Trans3 t; // 当前
  Trans3 p; // 父级

  for (int i = 0; i < tree->Nodes().size(); i++) {
    auto node = tree->Nodes()[i];
    if (node->avatar_id == AVATAR_NONE_ID) {
      // continue;
    }

    // 得到父级
    IMat parent = animator_->GetParentMat(node->parent);    

    IMat trans = is_t_pose ? node->tpose_relative.GetMatrix() : node->transformation;
    IMat global = trans * parent;

    t = global;
    p = parent;

    // TIPS：一个骨骼的起点，应该在他的父级骨骼上面。
    if (data_type == DataType::POINT) {
      obj->SetPosition(i, t.GetPosition());
    } else if (data_type == DataType::AXIS) {
      obj->SetTransform(i, t.GetPosition(), t.GetRotation(), t.GetScale());
    } else if (data_type == DataType::LINE) {
      if (node->parent) {
        obj->SetLine(i, t.GetPosition(), p.GetPosition());
      } else {
        obj->SetLine(i, IVec3(), IVec3());
      }
    }

    animator_->SetParentMat(node->index, global);
  }

  obj->SetDrawCount(tree->Nodes().size());
}

} // namespace ifire::game